﻿using System;
using BizElements.Core;

namespace BizElements.BusinessLayer
{
    /// <summary>Provides entity security logic.</summary>
    public interface IEntitySecurityProvider
    {
        /// <summary>Gets default options implemented in provider used if <b>AccessFilterOptions.None</b> is specified.</summary>
        AccessFilterOptions DefaultOptions { get; }

        /// <summary>Returns <b>true</b> if entity implements record ownership, i.e. if it has owner ID or team ID or unit ID field.</summary>
        /// <param name="entity">Business object.</param>
        /// <returns><b>true</b> if entity has at least one ownership field defined in its descriptor; otherwise <b>false</b></returns>
        bool ImplementsRecordOwnership(IBusinessObject entity);

        #region Apply access filter to queries.

        /// <summary>Modifies query so that it returns only entities that user is allowed to access.</summary>
        /// <param name="descriptor">Composite entity descriptor.</param>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="query">Query to which join clauses and additional criteria will be added as required.</param>
        /// <param name="options">Options/hints flags.</param>
        /// <param name="accessMode">Access mode: read, write or delete.</param>
        void ApplyAccessFilterToQuery(IBusinessObjectDescriptor descriptor, IActor user, SelectStatement query, AccessMode accessMode, AccessFilterOptions options);

        /// <summary>Modifies query so that it returns only entities that user is allowed to access.</summary>
        /// <param name="descriptor">Composite entity descriptor.</param>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="engine">Search engine to which join clauses and additional criteria will be added as required.</param>
        /// <param name="options">Options/hints flags.</param>
        /// <param name="accessMode">Access mode: read, write or delete.</param>
        void ApplyAccessFilterToSearchEngine(IBusinessObjectDescriptor descriptor, IActor user, SearchEngine engine, AccessMode accessMode, AccessFilterOptions options);

        /// <summary>Modifies query so that it returns only entities that user is allowed to access.</summary>
        /// <param name="descriptor">Composite entity descriptor.</param>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="sourceTable">Table which contains the entities. Aliases are permitted.</param>
        /// <param name="relations">Relation bucket to which join clauses will be added as required.</param>
        /// <param name="where">Search condition to which additional criteria will be added as required.</param>
        /// <param name="options">Options/hints flags.</param>
        /// <param name="accessMode">Access mode: read, write or delete.</param>
        void ApplyAccessFilterToQuery(IBusinessObjectDescriptor descriptor, IActor user, IDbTable sourceTable, RelationBucket relations, SearchCondition where, AccessMode accessMode, AccessFilterOptions options);

        #endregion

        #region CanRead, CanSave, CanCreate, CanUpdate, CanDelete, CanAssign methods.
        
        /// <summary>Check whether the user can read the specified entity.</summary>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="entity">Entity which the user is trying to access.</param>
        /// <returns><b>true</b> if user has privileges to access the entity; <b>false</b> otherwise.</returns>
        bool CanReadEntity(IActor user, IBusinessObject entity);
        

        /// <summary>Check whether the user can acces and save the specified entity.</summary>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="entity">Entity which the user is trying to save.</param>
        /// <returns><b>true</b> if user has privileges to access the entity; <b>false</b> otherwise.</returns>
        bool CanSaveEntity(IActor user, IBusinessObject entity);

        /// <summary>Checks whether the user can insert the provided entity. <b>RPC enabled.</b></summary>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="entity">Entity which the user is trying to insert into database.</param>
        /// <returns><b>true</b> if user has privileges to access the entity; <b>false</b> otherwise.</returns>
        bool CanCreateEntity(IActor user, IBusinessObject entity);

        /// <summary>Checks whether the user can update the provided entity. <b>RPC enabled.</b></summary>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="entity">Entity which the user is trying to insert into database.</param>
        /// <returns><b>true</b> if user has privileges to access the entity; <b>false</b> otherwise.</returns>
        bool CanUpdateEntity(IActor user, IBusinessObject entity);

        /// <summary>Check whether the user can acces and delete/deactivate the specified entity.</summary>
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="entity">Entity which the user is trying to delete.</param>
        /// <returns><b>true</b> if user has privileges to access the entity; <b>false</b> otherwise.</returns>
        bool CanDeleteEntity(IActor user, IBusinessObject entity);

        /// <summary>Checks whether the user can (re)assign ownership of the provided entity. <b>RPC enabled.</b></summary>        
        /// <param name="user">Actor for whom row access permissions are to be checked.</param>
        /// <param name="entity">Entity which the user is trying to insert into database.</param>
        /// <returns><b>true</b> if user has privileges to access the entity; <b>false</b> otherwise.</returns>
        bool CanAssignEntity(IActor user, IBusinessObject entity);

        #endregion

        #region FetchActorInfo.

        /// <summary>Fetches actor info associated with the provided username.</summary>
        /// <param name="username">Username.</param>
        /// <returns><see cref="IActor"/> or <b>null</b> it the specified username cannot be found.</returns>
        IActor FetchActorInfo(string username);

        #endregion
    }
}